iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0
Mobile Development

攜手神隊友ChatGPT:攝護腺自我照護App開發歷程!系列 第 24

D24-解碼Flutter官方文件,一起來了解動畫、圖像與異步處理解析(Animation & motion、Assets & images & icon、Async widgets)

  • 分享至 

  • xImage
  •  

Part1: 今日目標

1.前言
2.內容
3.提問
4.參考連結

Part2: 今日內容

1.前言

今天將接續昨天的文章內容,繼續介紹三個類別的 widgets,分別為: Animation and motion widgets、Assets, images, and icon widgets 和 Async widgets (Section_2~Section_4),讓我們開始吧!

2.內容: Part_3: User interface, Widget catalog

Section_1. Accessibility widgets

請參考昨天鐵人賽文章的介紹: D23-解碼Flutter官方文件,一起來了解無障礙小部件(Accessibility widgets)


Section_2. Animation and motion widgets

這個網頁主要介紹了 Flutter 中與動畫和運動相關的一些 widgets。以下是網頁中提到的一些主要 widgets 和相關的簡單描述:

  • AnimatedAlign: 當給定的對齊方式改變時,會在給定的持續時間內移動子 widget 的位置的動畫過渡。
  • AnimatedBuilder: 用於構建動畫的通用 widget。對於希望將動畫包含為更大構建函數的一部分的更複雜的 widgets 特別有用。
  • AnimatedContainer: 一個容器,可以在一段時間內逐漸改變其值。
  • AnimatedCrossFade: 在兩個給定的子 widget 之間交叉淡入淡出,並在它們的大小之間進行動畫。
  • AnimatedDefaultTextStyle: DefaultTextStyle 的動畫版本,可以自動過渡子 Text widget 的默認文本樣式。
    • Question: DefaultTextStyle 的動畫版本是什麼? Ans: AnimatedDefaultTextStyle 是 DefaultTextStyle 的動畫版本,它允許開發者在不同的文本樣式之間創建平滑的過渡動畫。Ref: AnimatedDefaultTextStyle class
  • Hero: 一個 widget,可以標記其子 widget 作為 hero 動畫的候選者。
    • Question: Hero動畫是什麼? Ans: Hero動畫是一種常見的UI設計模式,它創建了一個視覺連接,使用戶能夠更容易理解新視圖中的信息是從哪裡來的。Ref: Hero class
  • 其他: AnimatedList、AnimatedOpacity、AnimatedPositioned、AnimatedSize、AnimatedWidget、RotationTransition和ScaleTransition。

以上的每個 widget 都有其特定的用途和應用場景,開發者可以根據需要選擇合適的 widget 來實現各種動畫效果。

接者,我們選取AnimatedBuilder classAnimatedContainer class進行更詳細的介紹。

(1) AnimatedBuilder class
AnimatedBuilder 是 Flutter 中一個通用的 widget,用於構建動畫。以下是這個類別的一些主要資訊:

  • 主要功能:

    • AnimatedBuilder 是一個用於構建動畫的通用 widget,特別適用於希望將動畫包含為更大構建函數的一部分的更複雜的 widgets。
    • 它可以與任何 Listenable 的子類型一起使用,例如 ChangeNotifier 或 ValueNotifier,來觸發重建。
  • 性能優化:

    • 如果 builder 函數包含一個不依賴於傳遞給構造函數的動畫的子樹,那麼一次性構建該子樹會更高效,而不是在每個動畫刻度上重新構建它。
    • 如果一個預構建的子樹被傳遞為 child 參數,AnimatedBuilder 會將它傳回給 builder 函數,以便它可以被納入構建中。
      Question: 如何用更淺白例子說明? Ans: 如果builder函數中有一部分內容(子樹)不會隨著動畫的變化而變化,那麼最好一開始就構建這部分內容,而不是在每一帧都重新構建它,這樣可以提高性能。例如:
// Text('我不會變')就是一個預構建的子樹,它不會在每一帧都重新構建
AnimatedBuilder(
  animation: animation,
  builder: (BuildContext context, Widget? child) {
    // 這裡的 child 不會在每一帧都重新構建
    return SomeWidget(child: child);
  },
  child: const Text('我不會變'),
)
  • 使用範例:
// 這個範例是一個基本的AnimatedBuilder的使用,它會根據animation的當前值構建一個widget。
AnimatedBuilder(
  animation: animation,
  builder: (BuildContext context, Widget? child) {
    // 返回一個 widget,這個 widget 會根據 animation 的當前值進行構建
  },
)
  • 相關類別:

    • AnimatedWidget:對於沒有額外狀態的簡單情況,可以考慮使用 AnimatedWidget。
    • ListenableBuilder:如果一個 Listenable 沒有被監聽,可以考慮使用 ListenableBuilder 來提高可讀性。
      • Question: 沒有被監聽是什麼意思? Ans: 如果一個Listenable沒有被監聽,意味著沒有對象註冊來接收當Listenable對象改變時的通知。Ref: Listenable class
    • TweenAnimationBuilder:允許你對一個特定的屬性進行動畫,而不需要創建和管理一個AnimationController,這使得代碼變得更簡單和清晰。舉例:
      // Icon會在2秒內旋轉360度,而你不需要手動創建和管理AnimationController
      TweenAnimationBuilder(
        tween: Tween<double>(begin: 0, end: 2 * pi),
        duration: Duration(seconds: 2),
        builder: (BuildContext context, double angle, Widget? child) {
          return Transform.rotate(angle: angle, child: child);
        },
        child: Icon(Icons.refresh),
      )
      
  • 構造函數:
    這個構造函數定義了AnimatedBuilder,它需要一個Listenable類型的animation和一個TransitionBuilder類型的builder,並且可以選擇性地接收一個child。

AnimatedBuilder({
  Key? key,
  required Listenable animation,
  required TransitionBuilder builder,
  Widget? child,
})
  • 屬性和方法:
    • animation:通常是一個 Animation 對象,供構造函數使用。
    • builder:每次 animation 通知變更時調用。
    • child:要傳遞給 builder 函數的子 widget。
    • 包含基本的 widget 方法,如 createElement、createState、build 等。
      Question: 關於以上屬性和方法,用dart舉例說明
      Ans: 這些屬性和方法定義了AnimatedBuilder的行為,例如animation定義了動畫對象,builder定義了每次動畫變更時應該調用的方法,child是要傳遞給builder函數的子widget。 Ref: AnimatedBuilder class
// 這個例子中,AnimatedBuilder會根據animation的當前值來旋轉Icon。child參數是一個預構建的子樹,它會被傳入builder函數,這樣可以避免在每一帧都重新構建Icon。
AnimatedBuilder(
  animation: animation,
  builder: (BuildContext context, Widget? child) {
    // 在這裡,animation.value 是動畫的當前值,它會讓 Icon 旋轉
    return Transform.rotate(
      angle: animation.value,
      child: child, // 這裡的 child 是下面傳入的 Icon
    );
  },
  child: const Icon(Icons.star, size: 50), // 這個 Icon 會被傳入 builder 函數
)

(2) AnimatedContainer class
AnimatedContainer 是 Flutter 中一個用於創建隨時間逐漸改變其值的容器的 widget。以下是這個類別的一些主要資訊:

  • 主要功能:

    • AnimatedContainer 是 Container 的動畫版本,能夠在一段時間內自動地在舊值和新值之間進行動畫過渡。
    • 它可以自動地對不同的屬性進行動畫,例如尺寸、顏色、對齊等。
    • 它的子 widget 和後代不會進行動畫。Question: 舉例說明 Ans: 例子如下:
      // 在這個例子中,AnimatedContainer的寬度、高度和顏色會進行動畫過渡,但是內部的Text widget(子 widget)不會進行任何動畫過渡。
      AnimatedContainer(
        duration: Duration(seconds: 2),
        width: 100,
        height: 100,
        color: Colors.red,
        child: Text('Hello'),
      )
      
  • 使用場景:

    • 當開發者需要在不同參數之間生成簡單的隱式動畫時,這個類別會非常有用。

      • Question: 關於以下"隱式動畫",其英文名稱、定義和舉例說明? Ans:
        • 英文名稱: Implicit animations
        • 定義: 隱式動畫是指當 widget 的一個屬性改變時,系統會自動地在舊值和新值之間創建動畫過渡。
        • 舉例說明: Ref: ImplicitlyAnimatedWidget class
        // AnimatedOpacity會在_visible變量改變時,自動地在透明和不透明之間創建過渡動畫。
        AnimatedOpacity(
          opacity: _visible ? 1.0 : 0.0,
          duration: Duration(seconds: 2),
          child: const Text('Fade In/Out'),
        )
        
    • 對於更複雜的動畫,可能會需要使用 AnimatedWidget 的子類,例如 DecoratedBoxTransition,或者使用自定義的 AnimationController。

  • 構造函數:

AnimatedContainer({
  Key? key,
  AlignmentGeometry? alignment,
  EdgeInsetsGeometry? padding,
  Color? color,
  Decoration? decoration,
  BoxConstraints? constraints,
  EdgeInsetsGeometry? margin,
  Matrix4? transform,
  Widget? child,
  Clip clipBehavior = Clip.none,
  Curve curve = Curves.linear,
  required Duration duration,
  VoidCallback? onEnd,
})
  • 重要屬性:

    • alignment:在容器內對齊子 widget。
    • padding:在容器內部的空白空間。
    • color、decoration 和 foregroundDecoration:用於繪製容器的背景、裝飾和前景。
    • constraints:額外應用於子 widget 的約束。
    • margin:容器外部的空白空間。
    • transform 和 transformAlignment:在繪製容器之前應用的變換矩陣和變換對齊。
    • clipBehavior、curve、duration和onEnd。
  • 使用範例:

// 在這個例子中,AnimatedContainer 會在 1 秒的時間內改變其寬度、高度和顏色。
AnimatedContainer(
  duration: Duration(seconds: 1),
  width: 200.0,
  height: 200.0,
  color: Colors.red,
)

Section_3. Assets, images, and icon widgets

這個網頁主要介紹了與資源(Assets)、圖像(Images)和圖標(Icons)相關的小部件。提供了有關如何在Flutter中管理和顯示資源、圖像和圖標的基本信息,並且鏈接到了小部件目錄(widget catalog)以供查看更多小部件,以下是該網頁的主要內容:

  • 資源包(Asset Bundles)
    資源包含了應用程序可以使用的資源,例如圖像和字符串,訪問這些資源是異步的。

  • Material Design圖標(Material Design Icon)
    這是一個顯示Material Design圖標的小部件。

  • 圖像顯示小部件(Image Widget)
    這是一個用於顯示圖像的小部件。直接顯示dart:ui.Image的小部件


Section_4. Async widgets

這個網頁主要介紹了 Flutter 中與異步操作相關的一些 widgets。以下是網頁中提到的一些主要 widgets 和相關的簡單描述:

  • 共有兩種 widget:
    (1) FutureBuilder
    基於 Future 的最新快照交互來構建自己的 widget。當 Future 完成時,會根據 Future 的結果來構建 widget。

    (2) StreamBuilder
    基於 Stream 的最新快照交互來構建自己的 widget。它會根據與 Stream 的最後一次交互來構建 widget。

  • 使用場景:
    這些 widgets 都是用於構建依賴於異步數據的 UI。例如,當你從網絡請求數據時,可以使用 FutureBuilder 或 StreamBuilder 來構建 UI,這樣當數據到達時,UI 會自動更新。

  • 使用範例:

// 在這個 FutureBuilder 的例子中,當 fetchData 的 Future 完成時,會根據結果來構建 widget:如果有數據,會顯示數據;如果有錯誤,會顯示錯誤;如果 Future 還沒有完成,會顯示一個加載指示器。
FutureBuilder<String>(
  future: fetchData(), // 返回 Future<String>
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    if (snapshot.hasData) {
      return Text('Data: ${snapshot.data}');
    } else if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    }
    return CircularProgressIndicator(); // 加載中
  },
)

下一步將詳細介紹上述兩個 widget 的差別:
(1) FutureBuilder class
FutureBuilder 是 Flutter 中一個基於 Future 的最新快照交互來構建自己的 widget。以下是這個類別的一些主要資訊:

  • 主要功能:
    FutureBuilder 能夠根據與 Future 的最新快照交互來構建 widget。它會在 Future 完成時,根據 Future 的結果來構建 widget。

  • 管理 Future:

    • Future 必須在之前獲得,例如在 State.initState、State.didUpdateWidget 或 State.didChangeDependencies 期間。
    • Future 不應該在構造 FutureBuilder 時的 State.build 或 StatelessWidget.build 方法調用中創建。
    • 如果 Future 被創建在與 FutureBuilder 相同的時間,那麼每次 FutureBuilder 的父 widget 被重建時,異步任務都會重新開始。
  • 構建合同(Builder Contract):

    • 對於成功完成並帶有數據的 Future,builder 將被調用,並帶有以下快照之一或兩者:
      AsyncSnapshot.withData(ConnectionState.waiting, null)
      AsyncSnapshot.withData(ConnectionState.done, 'some data')
    • 如果 Future 完成並帶有一個錯誤,builder 將被調用,並帶有以下快照之一或兩者:
      AsyncSnapshot.withError(ConnectionState.done, 'some error', someStackTrace)
  • 使用範例:

// 在這個 FutureBuilder 的例子中,當 fetchData 的 Future 完成時,會根據結果來構建 widget:如果有數據,會顯示數據;如果有錯誤,會顯示錯誤;如果 Future 還沒有完成,會顯示一個加載指示器
FutureBuilder<String>(
  future: fetchData(), // 返回 Future<String>
  builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    if (snapshot.hasData) {
      return Text('Data: ${snapshot.data}');
    } else if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    }
    return CircularProgressIndicator(); // 加載中
  },
)

(2) StreamBuilder class
StreamBuilder 是 Flutter 中一個基於 Stream 的最新快照交互來構建自己的 widget。以下是這個類別的一些主要資訊:

  • 主要功能:

    • StreamBuilder 能夠根據與 Stream 的最新快照交互來構建 widget。
    • 它會在每次 Stream 產生一個新值時,根據該值來構建 widget。
    • StreamBuilder 的構建是由每次交互觸發的,使用 State.setState,但是與 Stream 的時序是解耦的。
  • 使用場景:

    • 當開發者需要構建依賴於異步數據流的 UI 時,這個類別會非常有用。
    • 例如,當你從一個 Stream 中監聽數據時,可以使用 * StreamBuilder 來構建 UI,這樣當新數據到達時,UI 會自動更新。
  • 構造函數:

StreamBuilder<T>({
  Key? key,
  T? initialData,
  required Stream<T> stream,
  required AsyncWidgetBuilder<T> builder,
})
  • 重要屬性:

    • stream:這個 StreamBuilder 監聽的 Stream。
    • initialData:創建初始快照的數據,這應該用於確保第一幀具有預期的值。
    • builder:每次 stream 產生一個新值時調用,用於構建 widget。
  • 使用範例:

// 在這個 StreamBuilder 的例子中,當 streamOfIntegers 的 Stream 產生一個新值時,會根據該值來構建 widget:如果有數據,會顯示數據;如果有錯誤,會顯示錯誤;如果 Stream 還沒有產生值,會顯示一個加載指示器
StreamBuilder<int>(
  stream: streamOfIntegers(), // 返回 Stream<int>
  builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
    if (snapshot.hasData) {
      return Text('Data: ${snapshot.data}');
    } else if (snapshot.hasError) {
      return Text('Error: ${snapshot.error}');
    }
    return CircularProgressIndicator(); // 加載中
  },
)

Question: FutureBuilder<T> classStreamBuilder<T> class具體的差別有哪些?
Ans:

  • 數據源:

    • FutureBuilder基於Future,它會等待Future完成並建構widget。
    • StreamBuilder基於Stream,它會監聽Stream上的數據並重建widget。
  • 使用場景:

    • FutureBuilder適合用於只需要一次數據的場景。
    • StreamBuilder適合用於會接收多次數據的場景。
  • 更新頻率:

    • FutureBuilder只會構建一次widget。
    • StreamBuilder會隨著Stream上的每條新數據重建widget。

3.提問

請搜尋此網頁: Question,即可查詢筆者在閱讀Flutter官方文件遇到的疑問和對應參考說明。

4.參考連結

當你學會了,嘗試去教人;當你獲得了,嘗試去給予
When you have learned, try to teach. When you get, try to give.
今天因緣際會被同事找去討論R language,順利解決套件版本衝突的問題,還順便交流幾個常用方法,非常開心有成就感🌟


上一篇
D23-解碼Flutter官方文件,一起來了解無障礙小部件(Accessibility widgets)
下一篇
D25-解碼Flutter官方文件,一起來了解基本和iOS 風格小部件(Basics、Cupertino (iOS-style) widgets)
系列文
攜手神隊友ChatGPT:攝護腺自我照護App開發歷程!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言